볡μ‘ν μ€μ²© ꡬ쑰μμ λ°μ΄ν° μ κ·Ό λ° μ‘°μμ λν κ°λ ₯ν μ μ΄κΆμ κ°λ°μμκ² λΆμ¬νλ, μ κ΅ν λ€λ¨κ³ κ°μ²΄ κ°λ‘μ±κΈ°λ₯Ό μν JavaScript νλ‘μ νΈλ€λ¬ 체μΈμ κ³ κΈ κ°λ μ νꡬν©λλ€.
JavaScript νλ‘μ νΈλ€λ¬ 체μΈ: λ€λ¨κ³ κ°μ²΄ κ°λ‘μ±κΈ° λ§μ€ν°νκΈ°
νλ JavaScript κ°λ° μμμμ νλ‘μ(Proxy) κ°μ²΄λ λμ κ°μ²΄μ λν κΈ°λ³Έμ μΈ μμ μ κ°λ‘μ±κ³ μ¬μ μν μ μλλ‘ ν΄μ£Όλ κ°λ ₯ν λ©ν νλ‘κ·Έλλ° λꡬμ λλ€. νλ‘μμ κΈ°λ³Έ μ¬μ©λ²μ μ μλ €μ Έ μμ§λ§, νλ‘μ νΈλ€λ¬ 체μ΄λ κΈ°μ μ μ΅νλ©΄ νΉν 볡μ‘ν λ€λ¨κ³ μ€μ²© κ°μ²΄λ₯Ό λ€λ£° λ μλ‘μ΄ μ°¨μμ μ μ΄ λ₯λ ₯μ μ»μ μ μμ΅λλ€. μ΄ κ³ κΈ κΈ°μ μ 볡μ‘ν ꡬ쑰 μ λ°μ κ±Έμ³ λ°μ΄ν°λ₯Ό μ κ΅νκ² κ°λ‘μ±κ³ μ‘°μν μ μκ² νμ¬, λ°μν μμ€ν μ€κ³, μΈλΆνλ μ κ·Ό μ μ΄ κ΅¬ν, 볡μ‘ν μ ν¨μ± κ²μ¬ κ·μΉ μ μ©μ μμ΄ νμν μ μ°μ±μ μ 곡ν©λλ€.
JavaScript νλ‘μμ ν΅μ¬ μ΄ν΄νκΈ°
νΈλ€λ¬ 체μΈμ λ°μ΄λ€κΈ° μ μ, JavaScript νλ‘μμ κΈ°λ³Έμ μ΄ν΄νλ κ²μ΄ μ€μν©λλ€. Proxy κ°μ²΄λ μμ±μμ λ κ°μ§ μΈμλ₯Ό μ λ¬νμ¬ μμ±λ©λλ€: target κ°μ²΄μ handler κ°μ²΄. targetμ νλ‘μκ° κ΄λ¦¬ν κ°μ²΄μ΄λ©°, handlerλ νλ‘μμ λν΄ μνλλ μμ
μ λν μ¬μ©μ μ§μ λμμ μ μνλ κ°μ²΄μ
λλ€.
handler κ°μ²΄μλ νΉμ μμ
μ κ°λ‘μ±λ λ©μλμΈ λ€μν νΈλ©(trap)μ΄ ν¬ν¨λμ΄ μμ΅λλ€. μΌλ°μ μΈ νΈλ©μ λ€μκ³Ό κ°μ΅λλ€:
get(target, property, receiver): μμ± μ κ·Όμ κ°λ‘μ±λλ€.set(target, property, value, receiver): μμ± ν λΉμ κ°λ‘μ±λλ€.has(target, property): `in` μ°μ°μλ₯Ό κ°λ‘μ±λλ€.deleteProperty(target, property): `delete` μ°μ°μλ₯Ό κ°λ‘μ±λλ€.apply(target, thisArg, argumentsList): ν¨μ νΈμΆμ κ°λ‘μ±λλ€.construct(target, argumentsList, newTarget): `new` μ°μ°μλ₯Ό κ°λ‘μ±λλ€.
Proxy μΈμ€ν΄μ€μ λν μμ
μ΄ μνλ λ, ν΄λΉ νΈλ©μ΄ handlerμ μ μλμ΄ μμΌλ©΄ ν΄λΉ νΈλ©μ΄ μ€νλ©λλ€. κ·Έλ μ§ μμΌλ©΄ μλ target κ°μ²΄μ λν΄ μμ
μ΄ μ§νλ©λλ€.
μ€μ²© κ°μ²΄μ κ³Όμ
볡μ‘ν μ ν리μΌμ΄μ μ κ΅¬μ± κ°μ²΄λ μ¬λ¬ μμ€μ κΆνμ κ°μ§ μ¬μ©μ νλ‘νμ λνλ΄λ κ³μΈ΅μ λ°μ΄ν° ꡬ쑰μ κ°μ΄ κΉκ² μ€μ²©λ κ°μ²΄λ₯Ό ν¬ν¨νλ μλ리μ€λ₯Ό μκ°ν΄ 보μμμ€. μ΄λ¬ν μ€μ²©μ μ΄λ€ μμ€μ μλ μμ±μλ μ ν¨μ± κ²μ¬, λ‘κΉ λλ μ κ·Ό μ μ΄μ κ°μ μΌκ΄λ λ‘μ§μ μ μ©ν΄μΌ ν λ, λ¨μΌνκ³ νλ©΄μ μΈ νλ‘μλ₯Ό μ¬μ©νλ κ²μ λΉν¨μ¨μ μ΄κ³ λ²κ±°λ‘μ΅λλ€.
μλ₯Ό λ€μ΄, μ¬μ©μ κ΅¬μ± κ°μ²΄λ₯Ό μμν΄ λ³΄μμμ€:
const userConfig = {
id: 123,
profile: {
name: 'Alice',
address: {
street: '123 Main St',
city: 'Anytown',
zip: '12345'
}
},
settings: {
theme: 'dark',
notifications: {
email: true,
sms: false
}
}
};
λͺ¨λ μμ± μ κ·Όμ λ‘κΉ νκ±°λ λͺ¨λ λ¬Έμμ΄ κ°μ΄ λΉμ΄ μμ§ μλλ‘ κ°μ νκ³ μΆλ€λ©΄, μΌλ°μ μΌλ‘ κ°μ²΄λ₯Ό μλμΌλ‘ μννκ³ μ¬κ·μ μΌλ‘ νλ‘μλ₯Ό μ μ©ν΄μΌ ν©λλ€. μ΄λ μν¬μ μΈ μ½λ(boilerplate code)μ μ±λ₯ μ€λ²ν€λλ₯Ό μ λ°ν μ μμ΅λλ€.
νλ‘μ νΈλ€λ¬ μ²΄μΈ μκ°
νλ‘μ νΈλ€λ¬ 체μΈμ κ°λ μ νλ‘μμ νΈλ©μ΄ λμμ μ§μ μ‘°μνκ±°λ κ°μ λ°ννλ λμ , λ€λ₯Έ νλ‘μλ₯Ό μμ±νκ³ λ°νν λ λνλ©λλ€. μ΄λ νλ‘μμ λν μμ μ΄ μ€μ²©λ νλ‘μμ λν μΆκ° μμ μΌλ‘ μ΄μ΄μ§ μ μλ 체μΈμ νμ±νμ¬, λμ κ°μ²΄μ κ³μΈ΅ ꡬ쑰λ₯Ό λ°μνλ μ€μ²© νλ‘μ ꡬ쑰λ₯Ό ν¨κ³Όμ μΌλ‘ μμ±ν©λλ€.
ν΅μ¬ μμ΄λμ΄λ νλ‘μμμ get νΈλ©μ΄ νΈμΆλκ³ μ κ·Όνλ μμ± μμ²΄κ° κ°μ²΄μΈ κ²½μ°, get νΈλ©μ΄ κ°μ²΄ μ체 λμ ν΄λΉ μ€μ²© κ°μ²΄μ λν μλ‘μ΄ Proxy μΈμ€ν΄μ€λ₯Ό λ°νν μ μλ€λ κ²μ
λλ€.
κ°λ¨ν μμ: μ¬λ¬ μμ€μμ μ κ·Ό λ‘κΉ
μ€μ²© κ°μ²΄ λ΄μμλ λͺ¨λ μμ± μ κ·Όμ λ‘κΉ νλ νλ‘μλ₯Ό λ§λ€μ΄ λ΄ μλ€.
function createLoggingProxy(obj, path = []) {
return new Proxy(obj, {
get(target, property, receiver) {
const currentPath = [...path, property].join('.');
console.log(`Accessing: ${currentPath}`);
const value = Reflect.get(target, property, receiver);
// If the value is an object and not null, and not a function (to avoid proxying functions themselves unless intended)
if (typeof value === 'object' && value !== null && !Array.isArray(value) && typeof value !== 'function') {
return createLoggingProxy(value, [...path, property]);
}
return value;
},
set(target, property, value, receiver) {
const currentPath = [...path, property].join('.');
console.log(`Setting: ${currentPath} to ${value}`);
return Reflect.set(target, property, value, receiver);
}
});
}
const userConfig = {
id: 123,
profile: {
name: 'Alice',
address: {
street: '123 Main St',
city: 'Anytown',
zip: '12345'
}
}
};
const proxiedUserConfig = createLoggingProxy(userConfig);
console.log(proxiedUserConfig.profile.name);
// Output:
// Accessing: profile
// Accessing: profile.name
// Alice
proxiedUserConfig.profile.address.city = 'Metropolis';
// Output:
// Accessing: profile
// Setting: profile.address.city to Metropolis
μ΄ μμμμ:
createLoggingProxyλ μ£Όμ΄μ§ κ°μ²΄μ λν νλ‘μλ₯Ό μμ±νλ ν©ν 리 ν¨μμ λλ€.getνΈλ©μ μ κ·Ό κ²½λ‘λ₯Ό λ‘κΉ ν©λλ€.- μ€μν μ μ, κ²μλ
valueκ° κ°μ²΄μΈ κ²½μ°, μ€μ²©λ κ°μ²΄μ λν μ νλ‘μλ₯Ό λ°ννκΈ° μν΄createLoggingProxyλ₯Ό μ¬κ·μ μΌλ‘ νΈμΆνλ€λ κ²μ λλ€. μ΄κ²μ΄ 체μΈμ΄ νμ±λλ λ°©μμ λλ€. setνΈλ© λν μμ μ¬νμ λ‘κΉ ν©λλ€.
proxiedUserConfig.profile.nameμ μ κ·Όν λ, 'profile'μ λν 첫 λ²μ§Έ get νΈλ©μ΄ νΈλ¦¬κ±°λ©λλ€. userConfig.profileμ΄ κ°μ²΄μ΄λ―λ‘ createLoggingProxyκ° λ€μ νΈμΆλμ΄ profile κ°μ²΄μ λν μ νλ‘μλ₯Ό λ°νν©λλ€. κ·Έλ° λ€μ, μ΄ *μλ‘μ΄* νλ‘μμ get νΈλ©μ΄ 'name'μ λν΄ νΈλ¦¬κ±°λ©λλ€. μ΄ μ€μ²©λ νλ‘μλ€μ ν΅ν΄ κ²½λ‘κ° μ¬λ°λ₯΄κ² μΆμ λ©λλ€.
λ€λ¨κ³ κ°λ‘μ±κΈ°λ₯Ό μν νΈλ€λ¬ 체μ΄λμ μ΄μ
- κ· μΌν λ‘μ§ μ μ©: λ°λ³΅μ μΈ μ½λ μμ΄ μ€μ²©λ κ°μ²΄μ λͺ¨λ μμ€μ κ±Έμ³ μΌκ΄λ λ‘μ§(μ ν¨μ± κ²μ¬, λ³ν, λ‘κΉ , μ κ·Ό μ μ΄)μ μ μ©ν©λλ€.
- μν¬μ μΈ μ½λ κ°μ: λͺ¨λ μ€μ²© κ°μ²΄μ λν μλ μν λ° νλ‘μ μμ±μ νΌν©λλ€. 체μΈμ μ¬κ·μ νΉμ±μ΄ μ΄λ₯Ό μλμΌλ‘ μ²λ¦¬ν©λλ€.
- ν₯μλ μ μ§ κ΄λ¦¬μ±: κ°λ‘μ±κΈ° λ‘μ§μ ν κ³³μ μ§μ€μμΌ μ λ°μ΄νΈ λ° μμ μ΄ ν¨μ¬ μ¬μμ§λλ€.
- λμ λμ: μ€μ²© νλ‘μλ₯Ό μννλ©΄μ λμμ μ¦μμμ λ³κ²½ν μ μλ λ§€μ° λμ μΈ λ°μ΄ν° ꡬ쑰λ₯Ό μμ±ν©λλ€.
κ³ κΈ μ¬μ© μ¬λ‘ λ° ν¨ν΄
νΈλ€λ¬ 체μ΄λ ν¨ν΄μ κ°λ¨ν λ‘κΉ μλ§ κ΅νλμ§ μμ΅λλ€. μ κ΅ν κΈ°λ₯μ ꡬννκΈ° μν΄ νμ₯λ μ μμ΅λλ€.
1. λ€λ¨κ³ λ°μ΄ν° μ ν¨μ± κ²μ¬
νΉμ νλκ° μ‘°κ±΄λΆλ‘ νμμ΄κ±°λ νΉμ νμ μ μ½ μ‘°κ±΄μ κ°λ 볡μ‘ν μμ κ°μ²΄ μ 체μμ μ¬μ©μ μ λ ₯μ κ²μ¦νλ κ²μ μμν΄ λ³΄μμμ€.
function createValidatingProxy(obj, path = [], validationRules = {}) {
return new Proxy(obj, {
get(target, property, receiver) {
const value = Reflect.get(target, property, receiver);
if (typeof value === 'object' && value !== null && !Array.isArray(value) && typeof value !== 'function') {
return createValidatingProxy(value, [...path, property], validationRules);
}
return value;
},
set(target, property, value, receiver) {
const currentPath = [...path, property].join('.');
const rules = validationRules[currentPath];
if (rules) {
if (rules.required && (value === null || value === undefined || value === '')) {
throw new Error(`Validation Error: ${currentPath} is required.`);
}
if (rules.type && typeof value !== rules.type) {
throw new Error(`Validation Error: ${currentPath} must be of type ${rules.type}.`);
}
if (rules.minLength && typeof value === 'string' && value.length < rules.minLength) {
throw new Error(`Validation Error: ${currentPath} must be at least ${rules.minLength} characters long.`);
}
// Add more validation rules as needed
}
return Reflect.set(target, property, value, receiver);
}
});
}
const userProfileSchema = {
name: { required: true, type: 'string', minLength: 2 },
age: { type: 'number', min: 18 },
contact: {
email: { required: true, type: 'string' },
phone: { type: 'string' }
}
};
const userProfile = {
name: '',
age: 25,
contact: {
email: '',
phone: '123-456-7890'
}
};
const proxiedUserProfile = createValidatingProxy(userProfile, [], userProfileSchema);
try {
proxiedUserProfile.name = 'Bo'; // Valid
proxiedUserProfile.contact.email = 'bo@example.com'; // Valid
console.log('Initial profile setup successful.');
} catch (error) {
console.error(error.message);
}
try {
proxiedUserProfile.name = 'B'; // Invalid - minLength
} catch (error) {
console.error(error.message);
}
try {
proxiedUserProfile.contact.email = ''; // Invalid - required
} catch (error) {
console.error(error.message);
}
try {
proxiedUserProfile.age = 'twenty'; // Invalid - type
} catch (error) {
console.error(error.message);
}
μ¬κΈ°μ createValidatingProxy ν¨μλ μ€μ²© κ°μ²΄μ λν νλ‘μλ₯Ό μ¬κ·μ μΌλ‘ μμ±ν©λλ€. set νΈλ©μ ν λΉμ νμ©νκΈ° μ μ μμ ν μ§μ λ μμ± κ²½λ‘(μ: 'profile.name')μ κ΄λ ¨λ μ ν¨μ± κ²μ¬ κ·μΉμ νμΈν©λλ€.
2. μΈλΆνλ μ κ·Ό μ μ΄
μ¬μ©μ μν μ΄λ 컨ν μ€νΈμ λ°λΌ νΉμ μμ±μ λν μ½κΈ° λλ μ°κΈ° μ κ·Όμ μ ννλ 보μ μ μ± μ ꡬνν©λλ€.
function createAccessControlledProxy(obj, accessConfig, path = []) {
// Default access: allow everything if not specified
const defaultAccess = { read: true, write: true };
return new Proxy(obj, {
get(target, property, receiver) {
const currentPath = [...path, property].join('.');
const config = accessConfig[currentPath] || defaultAccess;
if (!config.read) {
throw new Error(`Access Denied: Cannot read property '${currentPath}'.`);
}
const value = Reflect.get(target, property, receiver);
if (typeof value === 'object' && value !== null && !Array.isArray(value) && typeof value !== 'function') {
// Pass down the access config for nested properties
return createAccessControlledProxy(value, accessConfig, [...path, property]);
}
return value;
},
set(target, property, value, receiver) {
const currentPath = [...path, property].join('.');
const config = accessConfig[currentPath] || defaultAccess;
if (!config.write) {
throw new Error(`Access Denied: Cannot write to property '${currentPath}'.`);
}
return Reflect.set(target, property, value, receiver);
}
});
}
const sensitiveData = {
id: 'user-123',
personal: {
name: 'Alice',
ssn: '123-456-7890'
},
preferences: {
theme: 'dark',
language: 'en-US'
}
};
// Define access rules: Admin can read/write everything. User can only read preferences.
const accessRules = {
'personal.ssn': { read: false, write: false }, // Only admins can see SSN
'preferences': { read: true, write: true } // Users can manage preferences
};
// Simulate a user with limited access
const userAccessConfig = {
'personal.name': { read: true, write: true },
'personal.ssn': { read: false, write: false },
'preferences.theme': { read: true, write: true },
'preferences.language': { read: true, write: true }
// ... other preferences are implicitly readable/writable by defaultAccess
};
const proxiedSensitiveData = createAccessControlledProxy(sensitiveData, userAccessConfig);
console.log(proxiedSensitiveData.id); // Accessing 'id' - falls back to defaultAccess
console.log(proxiedSensitiveData.personal.name); // Accessing 'personal.name' - allowed
try {
console.log(proxiedSensitiveData.personal.ssn); // Attempt to read SSN
} catch (error) {
console.error(error.message);
// Output: Access Denied: Cannot read property 'personal.ssn'.
}
try {
proxiedSensitiveData.preferences.theme = 'light'; // Modifying preferences - allowed
console.log(`Theme changed to: ${proxiedSensitiveData.preferences.theme}`);
} catch (error) {
console.error(error.message);
}
try {
proxiedSensitiveData.personal.name = 'Alicia'; // Modifying name - allowed
console.log(`Name changed to: ${proxiedSensitiveData.personal.name}`);
} catch (error) {
console.error(error.message);
}
try {
proxiedSensitiveData.personal.ssn = '987-654-3210'; // Attempt to write SSN
} catch (error) {
console.error(error.message);
// Output: Access Denied: Cannot write to property 'personal.ssn'.
}
μ΄ μμλ νΉμ μμ± λλ μ€μ²© κ°μ²΄μ λν μ κ·Ό κ·μΉμ μ μνλ λ°©λ²μ 보μ¬μ€λλ€. createAccessControlledProxy ν¨μλ νλ‘μ 체μΈμ κ° μμ€μμ μ½κΈ° λ° μ°κΈ° μμ
μ΄ μ΄λ¬ν κ·μΉμ λν΄ νμΈλλλ‘ λ³΄μ₯ν©λλ€.
3. λ°μν λ°μ΄ν° λ°μΈλ© λ° μν κ΄λ¦¬
νλ‘μ νΈλ€λ¬ 체μΈμ λ°μν μμ€ν μ ꡬμΆνκΈ° μν κΈ°λ°μ λλ€. μμ±μ΄ μ€μ λ λ, UI λλ μ ν리μΌμ΄μ μ λ€λ₯Έ λΆλΆμμ μ λ°μ΄νΈλ₯Ό νΈλ¦¬κ±°ν μ μμ΅λλ€. μ΄λ λ§μ μ΅μ JavaScript νλ μμν¬ λ° μν κ΄λ¦¬ λΌμ΄λΈλ¬λ¦¬μ ν΅μ¬ κ°λ μ λλ€.
κ°μνλ λ°μν μ€ν μ΄λ₯Ό μκ°ν΄ 보μμμ€:
function createReactiveStore(initialState) {
const listeners = new Map(); // Map of property paths to arrays of callback functions
function subscribe(path, callback) {
if (!listeners.has(path)) {
listeners.set(path, []);
}
listeners.get(path).push(callback);
}
function notify(path, newValue) {
if (listeners.has(path)) {
listeners.get(path).forEach(callback => callback(newValue));
}
}
function createProxy(obj, currentPath = '') {
return new Proxy(obj, {
get(target, property, receiver) {
const value = Reflect.get(target, property, receiver);
const fullPath = currentPath ? `${currentPath}.${String(property)}` : String(property);
if (typeof value === 'object' && value !== null && !Array.isArray(value) && typeof value !== 'function') {
// Recursively create proxy for nested objects
return createProxy(value, fullPath);
}
return value;
},
set(target, property, value, receiver) {
const oldValue = target[property];
const result = Reflect.set(target, property, value, receiver);
const fullPath = currentPath ? `${currentPath}.${String(property)}` : String(property);
// Notify listeners if the value has changed
if (oldValue !== value) {
notify(fullPath, value);
// Also notify for parent paths if the change is significant, e.g., an object modification
if (currentPath) {
notify(currentPath, receiver); // Notify parent path with the whole updated object
}
}
return result;
}
});
}
const proxyStore = createProxy(initialState);
return { store: proxyStore, subscribe, notify };
}
const appState = {
user: {
name: 'Guest',
isLoggedIn: false
},
settings: {
theme: 'light',
language: 'en'
}
};
const { store, subscribe } = createReactiveStore(appState);
// Subscribe to changes
subscribe('user.name', (newName) => {
console.log(`User name changed to: ${newName}`);
});
subscribe('settings.theme', (newTheme) => {
console.log(`Theme changed to: ${newTheme}`);
});
subscribe('user', (updatedUser) => {
console.log('User object updated:', updatedUser);
});
// Simulate state updates
store.user.name = 'Bob';
// Output:
// User name changed to: Bob
store.settings.theme = 'dark';
// Output:
// Theme changed to: dark
store.user.isLoggedIn = true;
// Output:
// User object updated: { name: 'Bob', isLoggedIn: true }
store.user = { ...store.user, name: 'Alice' }; // Reassigning a nested object property
// Output:
// User name changed to: Alice
// User object updated: { name: 'Alice', isLoggedIn: true }
μ΄ λ°μν μ€ν μ΄ μμμμ, set νΈλ©μ ν λΉμ μνν λΏλ§ μλλΌ κ°μ΄ μ€μ λ‘ λ³κ²½λμλμ§λ νμΈν©λλ€. λ³κ²½λμλ€λ©΄, ν΄λΉ νΉμ μμ± κ²½λ‘μ ꡬλ
λ λͺ¨λ 리μ€λμκ² μλ¦Όμ νΈλ¦¬κ±°ν©λλ€. μ€μ²©λ κ²½λ‘λ₯Ό ꡬλ
νκ³ λ³κ²½ μ μ
λ°μ΄νΈλ₯Ό λ°μ μ μλ κΈ°λ₯μ νΈλ€λ¬ 체μ΄λμ μ§μ μ μΈ μ΄μ μ
λλ€.
κ³ λ € μ¬ν λ° λͺ¨λ² μ¬λ‘
νλ‘μ νΈλ€λ¬ 체μΈμ κ°λ ₯νμ§λ§, μ μ€ν κ³ λ €κ° νμν©λλ€:
- μ±λ₯ μ€λ²ν€λ: κ° νλ‘μ μμ± λ° νΈλ© νΈμΆμ μ½κ°μ μ€λ²ν€λλ₯Ό μΆκ°ν©λλ€. κ·Ήλλ‘ κΉμ μ€μ²© λλ λ§€μ° λΉλ²ν μμ μ κ²½μ°, ꡬνμ λ²€μΉλ§νΉνμμμ€. κ·Έλ¬λ μΌλ°μ μΈ μ¬μ© μ¬λ‘μμλ μ΄μ μ΄ μμ μ±λ₯ λΉμ©μ μννλ κ²½μ°κ° λ§μ΅λλ€.
- λλ²κΉ
볡μ‘μ±: νλ‘μλ κ°μ²΄λ₯Ό λλ²κΉ
νλ κ²μ λ μ΄λ €μΈ μ μμ΅λλ€. λΈλΌμ°μ κ°λ°μ λꡬμ λ‘κΉ
μ κ΄λ²μνκ² μ¬μ©νμμμ€. νΈλ©μ
receiverμΈμλ μ¬λ°λ₯Έ `this` 컨ν μ€νΈλ₯Ό μ μ§νλ λ° μ€μν©λλ€. - `Reflect` API: νΈλ© λ΄μμ νμ
ReflectAPI(μ:Reflect.get,Reflect.set)λ₯Ό μ¬μ©νμ¬ μ¬λ°λ₯Έ λμμ 보μ₯νκ³ , νΉν getter, setter λ° νλ‘ν νμ κ³Ό κ΄λ ¨νμ¬ νλ‘μμ λμ κ°μ λΆλ³ κ΄κ³λ₯Ό μ μ§νμμμ€. - μν μ°Έμ‘°: λμ κ°μ²΄μ μν μ°Έμ‘°μ μ μνμμμ€. νλ‘μ λ‘μ§μ΄ μ£ΌκΈ° κ²μ¬ μμ΄ λ§Ήλͺ©μ μΌλ‘ μ¬κ·νλ©΄ 무ν 루νμ λΉ μ§ μ μμ΅λλ€.
- λ°°μ΄ λ° ν¨μ: λ°°μ΄κ³Ό ν¨μλ₯Ό μ΄λ»κ² μ²λ¦¬ν μ§ κ²°μ νμμμ€. μ μμλ€μ μΌλ°μ μΌλ‘ μλνμ§ μλ ν ν¨μλ₯Ό μ§μ νλ‘μνμ§ μμΌλ©°, λͺ
μμ μΌλ‘ νλ‘κ·Έλλ°λμ§ μλ ν λ°°μ΄ μμΌλ‘ μ¬κ·νμ§ μμμΌλ‘μ¨ λ°°μ΄μ μ²λ¦¬ν©λλ€. λ°°μ΄μ νλ‘μνλ €λ©΄
push,popλ±κ³Ό κ°μ λ©μλμ λν νΉμ λ‘μ§μ΄ νμν μ μμ΅λλ€. - λΆλ³μ± λ κ°λ³μ±: νλ‘μλ κ°μ²΄κ° κ°λ³μ μ΄μ΄μΌ νλμ§ λΆλ³μ μ΄μ΄μΌ νλμ§ κ²°μ νμμμ€. μ μμλ€μ κ°λ³ κ°μ²΄λ₯Ό 보μ¬μ€λλ€. λΆλ³ ꡬ쑰μ κ²½μ°,
setνΈλ©μ μΌλ°μ μΌλ‘ μ€λ₯λ₯Ό λ°μμν€κ±°λ ν λΉμ 무μνκ³ ,getνΈλ©μ κΈ°μ‘΄ κ°μ λ°νν©λλ€. - `ownKeys` λ° `getOwnPropertyDescriptor`: ν¬κ΄μ μΈ κ°λ‘μ±κΈ°λ₯Ό μν΄
ownKeys(`for...in` 루ν λ°Object.keysμ©) λ°getOwnPropertyDescriptorμ κ°μ νΈλ© ꡬνμ κ³ λ €νμμμ€. μ΄λ μλ³Έ κ°μ²΄μ λμμ μμ ν λͺ¨λ°©ν΄μΌ νλ νλ‘μμ νμμ μ λλ€.
νλ‘μ νΈλ€λ¬ 체μΈμ κΈλ‘λ² μ μ©
μ¬λ¬ μμ€μμ λ°μ΄ν°λ₯Ό κ°λ‘μ±κ³ κ΄λ¦¬νλ λ₯λ ₯μ λ€μν κΈλ‘λ² μ ν리μΌμ΄μ 컨ν μ€νΈμμ νλ‘μ νΈλ€λ¬ 체μΈμ λ§€μ° μ μ©νκ² λ§λλλ€:
- κ΅μ ν(i18n) λ° νμ§ν(l10n): κ΅μ νλ μ ν리μΌμ΄μ μ μν 볡μ‘ν κ΅¬μ± κ°μ²΄λ₯Ό μμν΄ λ³΄μμμ€. νλ‘μλ₯Ό μ¬μ©νμ¬ μ¬μ©μ λ‘μΌμΌμ λ°λΌ λ²μλ λ¬Έμμ΄μ λμ μΌλ‘ κ°μ Έμ μ ν리μΌμ΄μ UI λ° λ°±μλμ λͺ¨λ μμ€μμ μΌκ΄μ±μ 보μ₯ν μ μμ΅λλ€. μλ₯Ό λ€μ΄, UI μμμ λν μ€μ²©λ ꡬμ±μ νλ‘μμ μν΄ κ°λ‘μ±μ§ λ‘μΌμΌλ³ ν μ€νΈ κ°μ κ°μ§ μ μμ΅λλ€.
- κΈλ‘λ² κ΅¬μ± κ΄λ¦¬: λκ·λͺ¨ λΆμ° μμ€ν μμ ꡬμ±μ κ³ λλ‘ κ³μΈ΅μ μ΄κ³ λμ μΌ μ μμ΅λλ€. νλ‘μλ μ΄λ¬ν μ€μ²© ꡬμ±μ κ΄λ¦¬νμ¬ κ·μΉμ μ μ©νκ³ , μ¬λ¬ λ§μ΄ν¬λ‘ μλΉμ€ κ°μ μ κ·Όμ λ‘κΉ νλ©°, μλΉμ€κ° μ μΈκ³ μ΄λμ λ°°ν¬λλ νκ²½ μμΈ λλ μ ν리μΌμ΄μ μνμ λ°λΌ μ¬λ°λ₯Έ ꡬμ±μ΄ μ μ©λλλ‘ λ³΄μ₯ν μ μμ΅λλ€.
- λ°μ΄ν° λκΈ°ν λ° μΆ©λ ν΄κ²°: μ¬λ¬ ν΄λΌμ΄μΈνΈ λλ μλ² κ°μ λ°μ΄ν°κ° λκΈ°νλλ λΆμ° μ ν리μΌμ΄μ (μ: μ€μκ° νμ νΈμ§ λꡬ)μμ νλ‘μλ 곡μ λ°μ΄ν° ꡬ쑰μ λν μ λ°μ΄νΈλ₯Ό κ°λ‘μ± μ μμ΅λλ€. μ΄λ€μ λκΈ°ν λ‘μ§μ κ΄λ¦¬νκ³ , μΆ©λμ κ°μ§νλ©°, μ§λ¦¬μ μμΉλ λ€νΈμν¬ μ§μ°μ κ΄κ³μμ΄ λͺ¨λ μ°Έμ¬ μν°ν°μ κ±Έμ³ μΌκ΄λκ² ν΄κ²° μ λ΅μ μ μ©νλ λ° μ¬μ©λ μ μμ΅λλ€.
- λ€μν μ§μμμμ 보μ λ° κ·μ μ€μ: λ―Όκ°ν λ°μ΄ν°λ₯Ό μ²λ¦¬νκ³ λ€μν κΈλ‘λ² κ·μ (μ: GDPR, CCPA)μ μ€μνλ μ ν리μΌμ΄μ μ κ²½μ°, νλ‘μ 체μΈμ μΈλΆνλ μ κ·Ό μ μ΄ λ° λ°μ΄ν° λ§μ€νΉ μ μ± μ μ μ©ν μ μμ΅λλ€. νλ‘μλ μ€μ²© κ°μ²΄μ κ°μΈ μλ³ μ 보(PII)μ λν μ κ·Όμ κ°λ‘μ±μ μ¬μ©μμ μ§μ λλ μ μΈλ λμμ λ°λΌ μ μ ν μ΅λͺ ν λλ μ κ·Ό μ νμ μ μ©νμ¬ λ€μν λ²μ νλ μμν¬ μ λ°μμ κ·μ μ€μλ₯Ό 보μ₯ν μ μμ΅λλ€.
κ²°λ‘
JavaScript νλ‘μ νΈλ€λ¬ 체μΈμ νΉν 볡μ‘νκ³ μ€μ²©λ λ°μ΄ν° ꡬ쑰 λ΄μμ κ°μ²΄ μμ μ λν μΈλΆνλ μ μ΄λ₯Ό κ°λ°μμκ² λΆμ¬νλ μ κ΅ν ν¨ν΄μ λλ€. νΈλ© ꡬν λ΄μμ νλ‘μλ₯Ό μ¬κ·μ μΌλ‘ μμ±νλ λ°©λ²μ μ΄ν΄ν¨μΌλ‘μ¨, κ³ λλ‘ λμ μ΄κ³ μ μ§ λ³΄μ κ°λ₯νλ©° κ²¬κ³ ν μ ν리μΌμ΄μ μ ꡬμΆν μ μμ΅λλ€. κ³ κΈ μ ν¨μ± κ²μ¬, κ°λ ₯ν μ κ·Ό μ μ΄, λ°μν μν κ΄λ¦¬ λλ 볡μ‘ν λ°μ΄ν° μ‘°μμ ꡬννλ κ΄κ³μμ΄, νλ‘μ νΈλ€λ¬ 체μΈμ κΈλ‘λ² κ·λͺ¨μ νλ JavaScript κ°λ°μ 볡μ‘μ±μ κ΄λ¦¬νκΈ° μν κ°λ ₯ν μ루μ μ μ 곡ν©λλ€.
JavaScript λ©ν νλ‘κ·Έλλ° μ¬μ μ κ³μνλ©΄μ, νλ‘μμ κ·Έ 체μ΄λ κΈ°λ₯μ κΉμ΄λ₯Ό νꡬνλ κ²μ μμ¬ν μ¬μ§ μμ΄ μ½λλ² μ΄μ€μμ μλ‘μ΄ μμ€μ μ°μν¨κ³Ό ν¨μ¨μ±μ μ΄μ΄μ€ κ²μ λλ€. κ°λ‘μ±κΈ°μ νμ λ°μλ€μ΄κ³ μ μΈκ³ μ¬μ©μλ₯Ό μν λμ± μ§λ₯μ μ΄κ³ λ°μμ μ΄λ©° μμ ν μ ν리μΌμ΄μ μ ꡬμΆνμμμ€.